#include "stm32f10x_gpio.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_nvic.h"
#include "stm32f10x_rcc.h"
#include "controller.h"
#include "stm32f10x_it.h"


static event_button_t event_callback;

static struct button_status_t button_status;

void controller_open( struct xcontroller *controller )
{
    GPIO_InitTypeDef GPIO_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    /* Enable Clock */
    RCC_APB2PeriphClockCmd(RF_RCC | BUTTON_RCC | RCC_APB2Periph_AFIO, ENABLE);

    /* RF */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Pin = RF_A_PIN;
    GPIO_Init(RF_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = RF_B_PIN;
    GPIO_Init(RF_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = RF_C_PIN;
    GPIO_Init(RF_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = RF_D_PIN;
    GPIO_Init(RF_PORT, &GPIO_InitStructure);

    /* Connect EXTI Line to GPIO Pin */
    GPIO_EXTILineConfig(RF_EXTI_PORT_SOURCE, RF_A_EXTI_PIN_SOURCE);
    GPIO_EXTILineConfig(RF_EXTI_PORT_SOURCE, RF_B_EXTI_PIN_SOURCE);
    GPIO_EXTILineConfig(RF_EXTI_PORT_SOURCE, RF_C_EXTI_PIN_SOURCE);
    GPIO_EXTILineConfig(RF_EXTI_PORT_SOURCE, RF_D_EXTI_PIN_SOURCE);

    /* Configure Button EXTI line */
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitStructure.EXTI_Line = RF_A_EXTI_LINE;
    EXTI_Init(&EXTI_InitStructure);
    EXTI_InitStructure.EXTI_Line = RF_B_EXTI_LINE;
    EXTI_Init(&EXTI_InitStructure);
    EXTI_InitStructure.EXTI_Line = RF_C_EXTI_LINE;
    EXTI_Init(&EXTI_InitStructure);
    EXTI_InitStructure.EXTI_Line = RF_D_EXTI_LINE;
    EXTI_Init(&EXTI_InitStructure);

    /* Enable and set Button EXTI Interrupt to the lowest priority */
    NVIC_InitStructure.NVIC_IRQChannel = RF_EXTI_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* On-Board Buttons */
    GPIO_InitStructure.GPIO_Pin = LEFT_PIN;
    GPIO_Init(BUTTON_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = CENTER_PIN;
    GPIO_Init(BUTTON_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = RIGHT_PIN;
    GPIO_Init(BUTTON_PORT, &GPIO_InitStructure);
    GPIO_EXTILineConfig(BUTTON_EXTI_PORT_SOURCE, LEFT_EXTI_PIN_SOURCE);
    GPIO_EXTILineConfig(BUTTON_EXTI_PORT_SOURCE, CENTER_EXTI_PIN_SOURCE);
    GPIO_EXTILineConfig(BUTTON_EXTI_PORT_SOURCE, RIGHT_EXTI_PIN_SOURCE);
    /* Configure Button EXTI line */
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitStructure.EXTI_Line = LEFT_EXTI_LINE;
    EXTI_Init(&EXTI_InitStructure);
    EXTI_InitStructure.EXTI_Line = RF_B_EXTI_LINE;
    EXTI_Init(&EXTI_InitStructure);
    EXTI_InitStructure.EXTI_Line = CENTER_EXTI_LINE;
    EXTI_Init(&EXTI_InitStructure);
    EXTI_InitStructure.EXTI_Line = RIGHT_EXTI_LINE;
    EXTI_Init(&EXTI_InitStructure);

    /* Enable and set Button EXTI Interrupt to the lowest priority */
    NVIC_InitStructure.NVIC_IRQChannel = BUTTON_EXTI_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    event_callback = controller->button_handler;
}

void rf_isr_handler(void)
{
    if(EXTI_GetITStatus(RF_A_EXTI_LINE) != RESET)
    {
        button_status.rf_a = 1;
        event_callback(CENTER, &button_status);
        EXTI_ClearITPendingBit(RF_A_EXTI_LINE);
    }
    if(EXTI_GetITStatus(RF_B_EXTI_LINE) != RESET)
    {
        button_status.rf_b = 1;
        event_callback(OK, &button_status);
        EXTI_ClearITPendingBit(RF_B_EXTI_LINE);
    }
    if(EXTI_GetITStatus(RF_C_EXTI_LINE) != RESET)
    {
        button_status.rf_c = 1;
        event_callback(LEFT, &button_status);
        EXTI_ClearITPendingBit(RF_C_EXTI_LINE);
    }
    if(EXTI_GetITStatus(RF_D_EXTI_LINE) != RESET)
    {
        button_status.rf_d = 1;
        event_callback(RIGHT, &button_status);
        EXTI_ClearITPendingBit(RF_D_EXTI_LINE);
    }
}

void button_isr_handler(void)
{
    if(EXTI_GetITStatus(LEFT_PIN) != RESET)
    {
        button_status.left= 1;
        event_callback(LEFT, &button_status);
        EXTI_ClearITPendingBit(LEFT_PIN);
    }
    if(EXTI_GetITStatus(CENTER_EXTI_LINE) != RESET)
    {
        button_status.center = 1;
        event_callback(CENTER, &button_status);
        EXTI_ClearITPendingBit(CENTER_EXTI_LINE);
    }
    if(EXTI_GetITStatus(RIGHT_EXTI_LINE) != RESET)
    {
        button_status.right = 1;
        event_callback(RIGHT, &button_status);
        EXTI_ClearITPendingBit(RIGHT_EXTI_LINE);
    }
}

struct button_status_t get_button_state(void)
{
    return button_status;
}

void register_callback(event_button_t callback)
{
    event_callback = callback;
}